#include "SPEmitter.h"

//---------------------------------------------------------------
// FileBufferStruct
//---------------------------------------------------------------
namespace SP
{
	SPFileBuffer::SPFileBuffer()
	{
		nNumByte = 0;
		pFileBuffer = NULL;
	}

	SPFileBuffer::~SPFileBuffer()
	{
		SAFE_DELETE( pFileBuffer );
	}

	void SPFileBuffer::CreateBuffer( int num )
	{
		nNumByte = num;
		pFileBuffer = new BYTE[num];
	}


	//---------------------------------------------------------------------------------------------------------
	void ModuleTransformBuffer::InitByModule( SPModuleEmitterTransform* pModule )
	{
		if ( SPModuleEmitterTranslation* p = dynamic_cast<SPModuleEmitterTranslation*>( pModule ) )
		{
			TYPE = 0;
		}

		if( SPModuleEmitterRotation* p = dynamic_cast<SPModuleEmitterRotation*>( pModule ) )
		{
			TYPE = 1;
		}

		if ( SPModuleEmitterScale* p = dynamic_cast<SPModuleEmitterScale*>( pModule ) )
		{
			TYPE = 2;
		}
		pModule->GetParm( start, end );
	}

	SPModuleEmitterTransform* ModuleTransformBuffer::ToModule()
	{
		SPModuleEmitterTransform* pNew;
		switch ( TYPE )
		{
		case 0: 
			pNew = new SPModuleEmitterTranslation();
			break;
		case 1:
			pNew = new SPModuleEmitterRotation();
			break;
		default:
			pNew = new SPModuleEmitterScale();
		}
		pNew->SetParm( start, end );
		return pNew;
	}

	//---------------------------------------------------------------------------------------------------------
	void ModuleParticleFloatBuffer::InitByModule( SPModuleParticleFloat* pModule )
	{			
		if ( dynamic_cast<SPModuleInitFloat*>( pModule ) )
		{
			TYPE = 1;
			SPModuleInitFloat* p = static_cast<SPModuleInitFloat*>( pModule );

			DistributionFloatBuffer* binfo;
			binfo = &init;
			p->GetConstant()->GetFileBufferInfo( &binfo->TYPE, &binfo->constant, &binfo->max, &binfo->min );				
		}
		else
		{
			SPModuleFloatOverLife* p = static_cast<SPModuleFloatOverLife*>( pModule );

			DistributionFloatBuffer* binfo;
			binfo = &start;
			p->GetStart()->GetFileBufferInfo( &binfo->TYPE, &binfo->constant, &binfo->max, &binfo->min );		

			binfo = &end;
			p->GetEnd()->GetFileBufferInfo( &binfo->TYPE, &binfo->constant, &binfo->max, &binfo->min );

		}			
	}

	SPModuleParticleFloat* ModuleParticleFloatBuffer::ToModule()
	{
		if ( TYPE == 1 )
		{
			SPModuleInitFloat* pNew = new SPModuleInitFloat();

			DistributionFloatBuffer* binfo = &init;
			pNew->GetConstant()->InitByFileBufferInfo( binfo->TYPE, binfo->constant, binfo->max, binfo->min );

			return pNew;
		}
		else
		{
			SPModuleFloatOverLife* pNew = new SPModuleFloatOverLife();

			DistributionFloatBuffer* binfo = &start;
			pNew->GetStart()->InitByFileBufferInfo( binfo->TYPE, binfo->constant, binfo->max, binfo->min );

			binfo = &end;
			pNew->GetEnd()->InitByFileBufferInfo( binfo->TYPE, binfo->constant, binfo->max, binfo->min );

			return pNew;
		}
	}

	//---------------------------------------------------------------------------------------------------------
	void ModuleParticleVectorBuffer::InitByModule( SPModuleParticleVector* pModule )
	{
		if ( dynamic_cast<SPModuleInitVector*>( pModule ) )
		{
			TYPE = 1;
			SPModuleInitVector* p = static_cast<SPModuleInitVector*>( pModule );

			DistributionFloatBuffer* binfox = &initX;
			DistributionFloatBuffer* binfoy = &initY;
			DistributionFloatBuffer* binfoz = &initZ;
			p->GetConstant()->GetFileBufferInfo( &binfox->TYPE, &binfox->constant, &binfox->max, &binfox->min,
				&binfoy->TYPE, &binfoy->constant, &binfoy->max, &binfoy->min,
				&binfoz->TYPE, &binfoz->constant, &binfoz->max, &binfoz->min );				
		}
		else
		{
			SPModuleVectorOverLife* p = static_cast<SPModuleVectorOverLife*>( pModule );

			DistributionFloatBuffer* binfox = &startX;
			DistributionFloatBuffer* binfoy = &startY;
			DistributionFloatBuffer* binfoz = &startZ;
			p->GetStart()->GetFileBufferInfo( &binfox->TYPE, &binfox->constant, &binfox->max, &binfox->min,
				&binfoy->TYPE, &binfoy->constant, &binfoy->max, &binfoy->min,
				&binfoz->TYPE, &binfoz->constant, &binfoz->max, &binfoz->min );		

			binfox = &endX;
			binfoy = &endY;
			binfoz = &endZ;
			p->GetEnd()->GetFileBufferInfo( &binfox->TYPE, &binfox->constant, &binfox->max, &binfox->min,
				&binfoy->TYPE, &binfoy->constant, &binfoy->max, &binfoy->min,
				&binfoz->TYPE, &binfoz->constant, &binfoz->max, &binfoz->min );		

		}					
	}

	SPModuleParticleVector* ModuleParticleVectorBuffer::ToModule()
	{
		if ( TYPE == 1 )
		{
			SPModuleInitVector* pNew = new SPModuleInitVector();

			DistributionFloatBuffer* binfox = &initX;
			DistributionFloatBuffer* binfoy = &initY;
			DistributionFloatBuffer* binfoz = &initZ;
			pNew->GetConstant()->InitByFileBufferInfo( binfox->TYPE, binfox->constant, binfox->max, binfox->min,
				binfoy->TYPE, binfoy->constant, binfoy->max, binfoy->min,
				binfoz->TYPE, binfoz->constant, binfoz->max, binfoz->min );

			return pNew;
		}
		else
		{
			SPModuleVectorOverLife* pNew = new SPModuleVectorOverLife();

			DistributionFloatBuffer* binfox = &startX;
			DistributionFloatBuffer* binfoy = &startY;
			DistributionFloatBuffer* binfoz = &startZ;
			pNew->GetStart()->InitByFileBufferInfo( binfox->TYPE, binfox->constant, binfox->max, binfox->min,
				binfoy->TYPE, binfoy->constant, binfoy->max, binfoy->min,
				binfoz->TYPE, binfoz->constant, binfoz->max, binfoz->min );

			binfox = &endX;
			binfoy = &endY;
			binfoz = &endZ;
			pNew->GetEnd()->InitByFileBufferInfo( binfox->TYPE, binfox->constant, binfox->max, binfox->min,
				binfoy->TYPE, binfoy->constant, binfoy->max, binfoy->min,
				binfoz->TYPE, binfoz->constant, binfoz->max, binfoz->min );

			return pNew;
		}
	}

	//---------------------------------------------------------------------------------------------------------
	void ModuleBeamTermialBuffer::InitByModule( SPModuleBeamTerminal* pModule )
	{
		bCPOverLife = pModule->m_bCPOverLife;
		bSPOverLife = pModule->m_bSPOverLife;
		vCPEnd = pModule->m_vCPEnd;
		vCPStart = pModule->m_vCPStart;
		vSPEnd = pModule->m_vSPEnd;
		vSPStart = pModule->m_vSPStart;
	}

	SPModuleBeamTerminal* ModuleBeamTermialBuffer::ToModule()
	{
		SPModuleBeamTerminal* pModule = new SPModuleBeamTerminal();
		pModule->m_bCPOverLife = bCPOverLife;
		pModule->m_bSPOverLife = bSPOverLife;
		pModule->m_vCPEnd = vCPEnd;		
		pModule->m_vCPStart = vCPStart;			
		pModule->m_vSPEnd = vSPEnd;			
		pModule->m_vSPStart = vSPStart;		
		return pModule;
	}

	//---------------------------------------------------------------------------------------------------------
	void ModuleBeamShaperBuffer::InitByModule( SPModuleBeamShape* pModule )
	{
		nShapeType = pModule->m_nShapeType;
		bOverLife = pModule->m_bOverLife;
		vStartCenterRadius = pModule->m_vStartCenterRadius;
		vEndCenterRadius = pModule->m_vEndCenterRadius;
	}

	SPModuleBeamShape* ModuleBeamShaperBuffer::ToModule()
	{
		SPModuleBeamShape* pModule = new SPModuleBeamShape();
		pModule->m_nShapeType = nShapeType;
		pModule->m_bOverLife = bOverLife;
		pModule->m_vStartCenterRadius = vStartCenterRadius;
		pModule->m_vEndCenterRadius = vEndCenterRadius;
		return pModule;
	}
}

//---------------------------------------------------------------
// Emitter
//---------------------------------------------------------------
namespace SP
{
	void SPEmitter::SetZero()
	{
		ClearModule();

		m_fEmitterLife = 0.0f;
		m_fEmitterDuration = 1.0f;
		m_fEmitterCurrentTime = 0.0f;
		m_fEmitterLoops = 1.0f;
	}

	SPEmitter::SPEmitter()
	{
		SetZero();

		m_bCopy = false;

		XMStoreFloat4x4( &m_mActorTransformation, XMMatrixIdentity() );
	}

	SPEmitter::SPEmitter( SPEmitter* archetype )
	{
		SetZero();

		m_fEmitterLoops = archetype->m_fEmitterLoops;
		m_fEmitterDuration = archetype->m_fEmitterDuration;
		m_fEmitterLife = 0.0f;
		m_fEmitterCurrentTime = 0.0f;

		std::list<SPModuleEmitterTransform*>::iterator it = archetype->m_EmitterTransformList.begin();
		for ( ; it != archetype->m_EmitterTransformList.end(); it++ )
		{
			if ( SPModuleEmitterScale* p = dynamic_cast<SPModuleEmitterScale*>( *it ) )
				m_EmitterTransformList.push_back( new SPModuleEmitterScale( p ) );
			if ( SPModuleEmitterRotation* p = dynamic_cast<SPModuleEmitterRotation*>( *it ) )
				m_EmitterTransformList.push_back( new SPModuleEmitterRotation( p ) );
			if ( SPModuleEmitterTranslation* p = dynamic_cast<SPModuleEmitterTranslation*>( *it) )
				m_EmitterTransformList.push_back( new SPModuleEmitterTranslation( p ) );
		}

		if ( m_pModuleBlendState )
			m_pModuleBlendState = 
				static_cast<SPModuleBlendState*>( archetype->m_pModuleBlendState->SpawnInstance() );
		if ( m_pModuleDepthStencilState )
			m_pModuleDepthStencilState = 
				static_cast<SPModuleDepthStencilState*>( archetype->m_pModuleDepthStencilState->SpawnInstance() );
		if ( m_pModuleRasterizerState )
			m_pModuleRasterizerState =
				static_cast<SPModuleRasterizerState*>( archetype->m_pModuleRasterizerState->SpawnInstance() );

		m_bCopy = true;
	}

	SPEmitter::~SPEmitter()
	{
		if ( m_bCopy )
		{
			std::list<SPModuleEmitterTransform*>::iterator it = m_EmitterTransformList.begin();
			for ( ; it != m_EmitterTransformList.end(); it++ )
			{
				SAFE_DELETE( *it );
			}
			m_EmitterTransformList.clear();

			SAFE_DELETE( m_pModuleBlendState );
			SAFE_DELETE( m_pModuleDepthStencilState );
			SAFE_DELETE( m_pModuleRasterizerState );
		}
	}

	void SPEmitter::Create( SPEmitter* archetype )
	{
		SetZero();

		m_fEmitterLoops = archetype->m_fEmitterLoops;
		m_fEmitterDuration = archetype->m_fEmitterDuration;
		m_fEmitterLife = 0.0f;
		m_fEmitterCurrentTime = 0.0f;

		std::list<SPModuleEmitterTransform*>::iterator it = archetype->m_EmitterTransformList.begin();
		for ( ; it != archetype->m_EmitterTransformList.end(); it++ )
		{
			if ( SPModuleEmitterScale* p = dynamic_cast<SPModuleEmitterScale*>( *it ) )
				m_EmitterTransformList.push_back( new SPModuleEmitterScale( p ) );
			if ( SPModuleEmitterRotation* p = dynamic_cast<SPModuleEmitterRotation*>( *it ) )
				m_EmitterTransformList.push_back( new SPModuleEmitterRotation( p ) );
			if ( SPModuleEmitterTranslation* p = dynamic_cast<SPModuleEmitterTranslation*>( *it) )
				m_EmitterTransformList.push_back( new SPModuleEmitterTranslation( p ) );
		}

		if ( m_pModuleBlendState )
			m_pModuleBlendState = 
			static_cast<SPModuleBlendState*>( archetype->m_pModuleBlendState->SpawnInstance() );
		if ( m_pModuleDepthStencilState )
			m_pModuleDepthStencilState = 
			static_cast<SPModuleDepthStencilState*>( archetype->m_pModuleDepthStencilState->SpawnInstance() );
		if ( m_pModuleRasterizerState )
			m_pModuleRasterizerState =
			static_cast<SPModuleRasterizerState*>( archetype->m_pModuleRasterizerState->SpawnInstance() );

		m_bCopy = true;
	}

	void SPEmitter::ClearModule()
	{
		m_EmitterTransformList.clear();

		m_pModuleEmitterColour = NULL;

		m_pModuleBlendState = NULL;
		m_pModuleRasterizerState = NULL;
		m_pModuleDepthStencilState = NULL;
	}

	void SPEmitter::Initialize()
	{
		m_fEmitterLife = 0.0f;
		m_fEmitterCurrentTime = 0.0f;
	}

	void SPEmitter::Advance( float fElapsedTime )
	{
		m_fEmitterCurrentTime += fElapsedTime;
		m_fEmitterLife = m_fEmitterCurrentTime / m_fEmitterDuration;
		m_fEmitterLife -= floor( m_fEmitterLife );
	}

	inline ID3D11BlendState* SPEmitter::GetBlendState()
	{
		if ( m_pModuleBlendState )
			return m_pModuleBlendState->GetState();
		return NULL;
	}

	inline ID3D11RasterizerState* SPEmitter::GetRasterizerState()
	{
		if ( m_pModuleRasterizerState )
			return m_pModuleRasterizerState->GetState();
		return NULL;
	}

	inline ID3D11DepthStencilState* SPEmitter::GetDepthStencilState()
	{
		if ( m_pModuleDepthStencilState )
			return m_pModuleDepthStencilState->GetState();
		return NULL;		
	}

	XMMATRIX SPEmitter::GetTransformMatrix()
	{
		XMMATRIX mWorldTransform = XMLoadFloat4x4( &m_mActorTransformation );
		std::list<SPModuleEmitterTransform*>::iterator it = m_EmitterTransformList.begin();
		for ( ; it != m_EmitterTransformList.end(); it++ )
			mWorldTransform *= ( *it )->GetTransformMatrix( m_fEmitterLife );
		return mWorldTransform;

		return XMMatrixIdentity();
	}

	bool SPEmitter::SetSPModule( SPModule* pModule )
	{
		if ( SPModuleBlendState* p = dynamic_cast<SPModuleBlendState*>(pModule) )
		{	
			m_pModuleBlendState = p ;
			return true;
		}

		if ( SPModuleDepthStencilState* p = dynamic_cast<SPModuleDepthStencilState*>(pModule) )
		{
			m_pModuleDepthStencilState =  p;
			return true;
		}

		if ( SPModuleRasterizerState* p = dynamic_cast<SPModuleRasterizerState*>(pModule) )
		{
			m_pModuleRasterizerState = p;
			return true;
		}

		if ( SPModuleEmitterTransform* p = dynamic_cast<SPModuleEmitterTransform*>( pModule ) )
		{
			m_EmitterTransformList.push_back( p );
			return true;
		}

		if ( SPModuleEmitterColour* p = dynamic_cast<SPModuleEmitterColour*>( pModule ) )
		{
			m_pModuleEmitterColour = p;
			return true;
		}

		return false;
	}

	void SPEmitter::CreateFileBuffer( SPFileBuffer* pFB )
	{
		int numbyte =  sizeof( EmitterFileHead );
		numbyte += m_EmitterTransformList.size() * sizeof( ModuleTransformBuffer );
		pFB->CreateBuffer( numbyte );
		BYTE* pBuf = pFB->pFileBuffer;

		EmitterFileHead head;
		ZeroMemory( &head, sizeof( head ) );

		head.nByteCount = numbyte;
		head.fEmitterDuration = m_fEmitterDuration;
		head.fEmitterLoops = m_fEmitterLoops;
		head.nModuleTranform = m_EmitterTransformList.size();

		if ( GetBlendState() )
		{
			head.bModuleBlendState = true;
			GetBlendState()->GetDesc( &head.BlendDesc );
		}

		if ( GetDepthStencilState() )
		{
			head.bModuleDepthStencilState = true;
			GetDepthStencilState()->GetDesc( &head.DepthStencilDesc );
		}

		if ( GetRasterizerState() )
		{
			head.bModuleRasterizer = true;
			GetRasterizerState()->GetDesc( &head.RasterizerDesc );
		}

		CopyMemory( pBuf, &head, sizeof( EmitterFileHead ) );
		
		// Transform Modules
		pBuf += sizeof( EmitterFileHead );
		std::list<SPModuleEmitterTransform*>::iterator it = m_EmitterTransformList.begin();
		for ( ; it != m_EmitterTransformList.end(); it++ )
		{
			ModuleTransformBuffer mtb;
			mtb.InitByModule( *it );
			CopyMemory( pBuf, &mtb, sizeof( ModuleTransformBuffer ) );
			pBuf += sizeof( ModuleTransformBuffer );
		}
	}

	void SPEmitter::CreateFromFileBuffer( BYTE* pBufPtr )
	{
		EmitterFileHead* phead= (EmitterFileHead*)pBufPtr;

		m_fEmitterDuration = phead->fEmitterDuration;
		m_fEmitterLoops = phead->fEmitterLoops;

		if ( phead->bModuleBlendState )
		{
			m_pModuleBlendState = new SPModuleBlendState();
			m_pModuleBlendState->SetStateDesc( phead->BlendDesc );
		}

		if ( phead->bModuleDepthStencilState )
		{
			m_pModuleDepthStencilState = new SPModuleDepthStencilState();
			m_pModuleDepthStencilState->SetStateDesc( phead->DepthStencilDesc );
		}

		if ( phead->bModuleRasterizer )
		{
			m_pModuleRasterizerState = new SPModuleRasterizerState();
			m_pModuleRasterizerState->SetStateDesc( phead->RasterizerDesc );
		}

		ModuleTransformBuffer* pBuf = (ModuleTransformBuffer*)( pBufPtr + sizeof( EmitterFileHead ) );
		for ( int i = 0; i < phead->nModuleTranform; i++ )
		{
			m_EmitterTransformList.push_back( pBuf[i].ToModule() );
		}
	}

}